import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols';
/**
 * 流程图[](img.zhufengpeixun.cn/ReactChildrenmap.jpg)
 * @param {} children
 * @param {*} func
 * @param {*} context
 * result 会把我们映射出来的所有节点都放在result 里面
 */

const SEPARATOR = '.'; // 分隔符 开头的分隔符
const SUB_SEPARATOP = ';'; // 子分隔 中间的分隔符

function mapChildren(children, mapfuntion, context) {
    console.log(children);
    const result = [];
    mapIntoWithKeyProfixInteral(children, result, null, mapfuntion, context);
    return result;
}
/**
 *prefix 是渲染前的的几点key 最终key的/前面的那部分
 * @param {} children
 * @param {*} result
 * @param {*} prefix
 * @param {*} mapfuntion
 * @param {*} context
 */
function mapIntoWithKeyProfixInteral(
    children,
    result,
    prefix,
    mapfuntion,
    context
) {
    if (prefix !== null) {
        prefix = prefix + '/'; // 0:0/
    }
    // traverseContext 遍历上下文
    const traverseContext = { result, prefix, mapfuntion, context };
    traverseAllChildren(
        children,
        '',
        mapSingleChildIntoContext,
        traverseContext
    );
}
function traverseAllChildren(
    children,
    nameSoFar,
    mapSingleChildIntoContext,
    traverseContext
) {
    let type = typeof children;
    if (
        type === 'string' ||
        type === 'number' ||
        (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)
    ) {
        mapSingleChildIntoContext(
            traverseContext,
            children,
            nameSoFar === ''
                ? SEPARATOR + getComponentKey(children, 0)
                : nameSoFar
        );
    } else if (Array.isArray(children)) {
        // 如果传进来的nameSoFar 是空的. 前缀就是。, 否则就是:
        // 第二次进来的时候nameSoFar = .0  nextNamePrefix = :
        let nextNamePrefix =
            nameSoFar === '' ? SEPARATOR : nameSoFar + SUB_SEPARATOP;
        for (let i = 0; i < children.length; i++) {
            let child = children[i];
            let nextName = nextNamePrefix + getComponentKey(child, i);
            traverseAllChildren(
                child,
                nextName,
                mapSingleChildIntoContext,
                traverseContext
            );
        }
    }
}
function getComponentKey(component, index) {
    return component.key || index.toString(36);
}

function mapSingleChildIntoContext(traverseContext, children, childKey) {
    const { result, prefix, mapfuntion, context } = traverseContext;
    let mappedChid = mapfuntion.call(context, children);
    if (Array.isArray(mappedChid)) {
        mapIntoWithKeyProfixInteral(
            mappedChid,
            result,
            childKey,
            (c) => c,
            context
        );
    } else {
        result.push({ ...mappedChid, key: prefix + childKey });
    }
}
export { mapChildren as map };
